// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "GameFramework/SaveGame.h"
#include "SubtitleDisplayOptions.h"

#include "UObject/ObjectPtr.h"
#include "LyraSettingsShared.generated.h"

class UObject;
struct FFrame;

// 色盲模式枚举
UENUM(BlueprintType)
enum class EColorBlindMode : uint8
{
	Off, // 关闭
	Deuteranope, // 绿色弱/盲（绿色弱视）
	Protanope, // 红色弱/盲（红色弱视）
	Tritanope // 蓝色弱/盲（蓝色弱视）
};

// 后台音频允许设置枚举
UENUM(BlueprintType)
enum class ELyraAllowBackgroundAudioSetting : uint8
{
	Off, // 关闭
	AllSounds, // 所有声音

	Num UMETA(Hidden), // 数量（隐藏）
};

// 游戏手柄灵敏度枚举
UENUM(BlueprintType)
enum class ELyraGamepadSensitivity : uint8
{
	Invalid = 0		UMETA(Hidden), // 无效

	Slow			UMETA(DisplayName = "01 - Slow"), // 慢速
	SlowPlus		UMETA(DisplayName = "02 - Slow+"), // 慢速+
	SlowPlusPlus	UMETA(DisplayName = "03 - Slow++"), // 慢速++
	Normal			UMETA(DisplayName = "04 - Normal"), // 正常
	NormalPlus		UMETA(DisplayName = "05 - Normal+"), // 正常+
	NormalPlusPlus	UMETA(DisplayName = "06 - Normal++"), // 正常++
	Fast			UMETA(DisplayName = "07 - Fast"), // 快速
	FastPlus		UMETA(DisplayName = "08 - Fast+"), // 快速+
	FastPlusPlus	UMETA(DisplayName = "09 - Fast++"), // 快速++
	Insane			UMETA(DisplayName = "10 - Insane"), // 极速

	MAX				UMETA(Hidden), // 最大值
};

class ULyraLocalPlayer;

/**
 * Lyra共享设置类
 * 共享设置作为USaveGame系统的一部分存储，这些设置不是机器特定的，可以安全地存储在云端并共享
 */
UCLASS()
class ULyraSettingsShared : public ULocalPlayerSaveGame
{
	GENERATED_BODY()

public:
	// 设置更改事件声明
	DECLARE_EVENT_OneParam(ULyraSettingsShared, FOnSettingChangedEvent, ULyraSettingsShared* Settings);
	FOnSettingChangedEvent OnSettingChanged;

public:

	ULyraSettingsShared();

	//~ULocalPlayerSaveGame接口
	/**
	 * 获取最新数据版本
	 * @return 数据版本号
	 */
	int32 GetLatestDataVersion() const override;
	//~ULocalPlayerSaveGame接口结束

	/**
	 * 检查设置是否已修改
	 * @return 如果已修改返回true，否则返回false
	 */
	bool IsDirty() const { return bIsDirty; }
	
	/**
	 * 清除脏标记
	 */
	void ClearDirtyFlag() { bIsDirty = false; }

	/**
	 * 创建临时设置对象
	 * @param LocalPlayer 本地玩家对象
	 * @return 共享设置实例
	 */
	static ULyraSettingsShared* CreateTemporarySettings(const ULyraLocalPlayer* LocalPlayer);
	
	/**
	 * 同步加载设置对象
	 * @param LocalPlayer 本地玩家对象
	 * @return 共享设置实例
	 */
	static ULyraSettingsShared* LoadOrCreateSettings(const ULyraLocalPlayer* LocalPlayer);

	// 设置加载事件委托
	DECLARE_DELEGATE_OneParam(FOnSettingsLoadedEvent, ULyraSettingsShared* Settings);

	/**
	 * 异步加载设置对象
	 * @param LocalPlayer 本地玩家对象
	 * @param Delegate 加载完成后的回调委托
	 * @return 如果成功开始加载返回true，否则返回false
	 */
	static bool AsyncLoadOrCreateSettings(const ULyraLocalPlayer* LocalPlayer, FOnSettingsLoadedEvent Delegate);

	/**
	 * 保存设置到磁盘
	 */
	void SaveSettings();

	/**
	 * 应用当前设置到玩家
	 */
	void ApplySettings();
	
public:
	////////////////////////////////////////////////////////
	// 色盲选项

	/**
	 * 获取色盲模式
	 * @return 色盲模式
	 */
	UFUNCTION()
	EColorBlindMode GetColorBlindMode() const;
	
	/**
	 * 设置色盲模式
	 * @param InMode 色盲模式
	 */
	UFUNCTION()
	void SetColorBlindMode(EColorBlindMode InMode);

	/**
	 * 获取色盲强度
	 * @return 色盲强度
	 */
	UFUNCTION()
	int32 GetColorBlindStrength() const;
	
	/**
	 * 设置色盲强度
	 * @param InColorBlindStrength 色盲强度
	 */
	UFUNCTION()
	void SetColorBlindStrength(int32 InColorBlindStrength);

private:
	UPROPERTY()
	EColorBlindMode ColorBlindMode = EColorBlindMode::Off; // 色盲模式，默认为关闭

	UPROPERTY()
	int32 ColorBlindStrength = 10; // 色盲强度，默认为10

    ////////////////////////////////////////////////////////
	// 游戏手柄震动
public:
	/**
	 * 获取力反馈是否启用
	 * @return 如果力反馈启用返回true，否则返回false
	 */
	UFUNCTION()
	bool GetForceFeedbackEnabled() const { return bForceFeedbackEnabled; }

	/**
	 * 设置力反馈启用状态
	 * @param NewValue 新的启用状态
	 */
	UFUNCTION()
	void SetForceFeedbackEnabled(const bool NewValue) { ChangeValueAndDirty(bForceFeedbackEnabled, NewValue); }
	
private:
	/** 当使用控制器时是否启用力反馈？ */
	UPROPERTY()
	bool bForceFeedbackEnabled = true; // 力反馈启用状态，默认为true

	////////////////////////////////////////////////////////
	// 游戏手柄死区
public:
	/** 获取游戏手柄移动摇杆死区值 */
	UFUNCTION()
	float GetGamepadMoveStickDeadZone() const { return GamepadMoveStickDeadZone; }

	/** 设置游戏手柄移动摇杆死区值 */
	UFUNCTION()
	void SetGamepadMoveStickDeadZone(const float NewValue) { ChangeValueAndDirty(GamepadMoveStickDeadZone, NewValue); }

	/** 获取游戏手柄视角摇杆死区值 */
	UFUNCTION()
	float GetGamepadLookStickDeadZone() const { return GamepadLookStickDeadZone; }

	/** 设置游戏手柄视角摇杆死区值 */
	UFUNCTION()
	void SetGamepadLookStickDeadZone(const float NewValue) { ChangeValueAndDirty(GamepadLookStickDeadZone, NewValue); }

private:
	/** 保存游戏手柄移动摇杆死区值 */
	UPROPERTY()
	float GamepadMoveStickDeadZone; // 游戏手柄移动摇杆死区

	/** 保存游戏手柄视角摇杆死区值 */
	UPROPERTY()
	float GamepadLookStickDeadZone; // 游戏手柄视角摇杆死区

	////////////////////////////////////////////////////////
	// 游戏手柄扳机触觉反馈
public:
	/** 获取扳机触觉反馈是否启用 */
	UFUNCTION()
	bool GetTriggerHapticsEnabled() const { return bTriggerHapticsEnabled; }
	
	/** 设置扳机触觉反馈启用状态 */
	UFUNCTION()
	void SetTriggerHapticsEnabled(const bool NewValue) { ChangeValueAndDirty(bTriggerHapticsEnabled, NewValue); }

	/** 获取扳机拉动是否使用触觉阈值 */
	UFUNCTION()
	bool GetTriggerPullUsesHapticThreshold() const { return bTriggerPullUsesHapticThreshold; }
	
	/** 设置扳机拉动是否使用触觉阈值 */
	UFUNCTION()
	void SetTriggerPullUsesHapticThreshold(const bool NewValue) { ChangeValueAndDirty(bTriggerPullUsesHapticThreshold, NewValue); }

	/** 获取扳机触觉反馈强度 */
	UFUNCTION()
	uint8 GetTriggerHapticStrength() const { return TriggerHapticStrength; }
	
	/** 设置扳机触觉反馈强度 */
	UFUNCTION()
	void SetTriggerHapticStrength(const uint8 NewValue) { ChangeValueAndDirty(TriggerHapticStrength, NewValue); }

	/** 获取扳机触觉反馈起始位置 */
	UFUNCTION()
	uint8 GetTriggerHapticStartPosition() const { return TriggerHapticStartPosition; }
	
	/** 设置扳机触觉反馈起始位置 */
	UFUNCTION()
	void SetTriggerHapticStartPosition(const uint8 NewValue) { ChangeValueAndDirty(TriggerHapticStartPosition, NewValue); }
	
private:
	/** 扳机触觉反馈是否启用？ */
	UPROPERTY()
	bool bTriggerHapticsEnabled = false; // 扳机触觉反馈启用状态，默认为false
	
	/** 游戏是否使用触觉反馈作为判断按钮按下的阈值？ */
	UPROPERTY()
	bool bTriggerPullUsesHapticThreshold = true; // 扳机拉动使用触觉阈值，默认为true
	
	/** 扳机触觉反馈的强度 */
	UPROPERTY()
	uint8 TriggerHapticStrength = 8; // 扳机触觉反馈强度，默认为8
	
	/** 扳机触觉反馈的起始位置 */
	UPROPERTY()
	uint8 TriggerHapticStartPosition = 0; // 扳机触觉反馈起始位置，默认为0

	////////////////////////////////////////////////////////
	// 字幕
public:
	/** 获取字幕是否启用 */
	UFUNCTION()
	bool GetSubtitlesEnabled() const { return bEnableSubtitles; }
	
	/** 设置字幕启用状态 */
	UFUNCTION()
	void SetSubtitlesEnabled(bool Value) { ChangeValueAndDirty(bEnableSubtitles, Value); }

	/** 获取字幕文本大小 */
	UFUNCTION()
	ESubtitleDisplayTextSize GetSubtitlesTextSize() const { return SubtitleTextSize; }
	
	/** 设置字幕文本大小 */
	UFUNCTION()
	void SetSubtitlesTextSize(ESubtitleDisplayTextSize Value) { ChangeValueAndDirty(SubtitleTextSize, Value); ApplySubtitleOptions(); }

	/** 获取字幕文本颜色 */
	UFUNCTION()
	ESubtitleDisplayTextColor GetSubtitlesTextColor() const { return SubtitleTextColor; }
	
	/** 设置字幕文本颜色 */
	UFUNCTION()
	void SetSubtitlesTextColor(ESubtitleDisplayTextColor Value) { ChangeValueAndDirty(SubtitleTextColor, Value); ApplySubtitleOptions(); }

	/** 获取字幕文本边框 */
	UFUNCTION()
	ESubtitleDisplayTextBorder GetSubtitlesTextBorder() const { return SubtitleTextBorder; }
	
	/** 设置字幕文本边框 */
	UFUNCTION()
	void SetSubtitlesTextBorder(ESubtitleDisplayTextBorder Value) { ChangeValueAndDirty(SubtitleTextBorder, Value); ApplySubtitleOptions(); }

	/** 获取字幕背景不透明度 */
	UFUNCTION()
	ESubtitleDisplayBackgroundOpacity GetSubtitlesBackgroundOpacity() const { return SubtitleBackgroundOpacity; }
	
	/** 设置字幕背景不透明度 */
	UFUNCTION()
	void SetSubtitlesBackgroundOpacity(ESubtitleDisplayBackgroundOpacity Value) { ChangeValueAndDirty(SubtitleBackgroundOpacity, Value); ApplySubtitleOptions(); }

	/**
	 * 应用字幕选项
	 */
	void ApplySubtitleOptions();

private:
	UPROPERTY()
	bool bEnableSubtitles = true; // 字幕启用状态，默认为true

	UPROPERTY()
	ESubtitleDisplayTextSize SubtitleTextSize = ESubtitleDisplayTextSize::Medium; // 字幕文本大小，默认为中等

	UPROPERTY()
	ESubtitleDisplayTextColor SubtitleTextColor = ESubtitleDisplayTextColor::White; // 字幕文本颜色，默认为白色

	UPROPERTY()
	ESubtitleDisplayTextBorder SubtitleTextBorder = ESubtitleDisplayTextBorder::None; // 字幕文本边框，默认为无

	UPROPERTY()
	ESubtitleDisplayBackgroundOpacity SubtitleBackgroundOpacity = ESubtitleDisplayBackgroundOpacity::Medium; // 字幕背景不透明度，默认为中等

	////////////////////////////////////////////////////////
	// 共享音频设置
public:
	/** 获取后台音频允许设置 */
	UFUNCTION()
	ELyraAllowBackgroundAudioSetting GetAllowAudioInBackgroundSetting() const { return AllowAudioInBackground; }
	
	/** 设置后台音频允许设置 */
	UFUNCTION()
	void SetAllowAudioInBackgroundSetting(ELyraAllowBackgroundAudioSetting NewValue);

	/**
	 * 应用后台音频设置
	 */
	void ApplyBackgroundAudioSettings();

private:
	UPROPERTY()
	ELyraAllowBackgroundAudioSetting AllowAudioInBackground = ELyraAllowBackgroundAudioSetting::Off; // 后台音频允许设置，默认为关闭

	////////////////////////////////////////////////////////
	// 文化/语言
public:
	/** 获取待处理的文化设置 */
	const FString& GetPendingCulture() const;

	/** 设置待处理的文化设置 */
	void SetPendingCulture(const FString& NewCulture);

	/** 文化设置更改时调用 */
	void OnCultureChanged();

	/** 清除待处理的文化设置 */
	void ClearPendingCulture();

	/** 检查是否使用默认文化设置 */
	bool IsUsingDefaultCulture() const;

	/** 重置为默认文化设置 */
	void ResetToDefaultCulture();
	
	/** 检查是否应重置为默认文化设置 */
	bool ShouldResetToDefaultCulture() const { return bResetToDefaultCulture; }
	
	/** 应用文化设置 */
	void ApplyCultureSettings();
	
	/** 重置文化设置为当前设置 */
	void ResetCultureToCurrentSettings();

private:
	/** 待处理的文化设置 */
	UPROPERTY(Transient)
	FString PendingCulture; // 待处理的文化设置字符串

	/* 如果为true，则重置文化设置为默认值 */
	bool bResetToDefaultCulture = false; // 重置为默认文化设置标志，默认为false

	////////////////////////////////////////////////////////
	// 游戏手柄灵敏度
public:
	/** 获取鼠标水平灵敏度 */
	UFUNCTION()
	double GetMouseSensitivityX() const { return MouseSensitivityX; }
	
	/** 设置鼠标水平灵敏度 */
	UFUNCTION()
	void SetMouseSensitivityX(double NewValue) { ChangeValueAndDirty(MouseSensitivityX, NewValue); ApplyInputSensitivity(); }

	/** 获取鼠标垂直灵敏度 */
	UFUNCTION()
	double GetMouseSensitivityY() const { return MouseSensitivityY; }
	
	/** 设置鼠标垂直灵敏度 */
	UFUNCTION()
	void SetMouseSensitivityY(double NewValue) { ChangeValueAndDirty(MouseSensitivityY, NewValue); ApplyInputSensitivity(); }

	/** 获取瞄准倍率 */
	UFUNCTION()
	double GetTargetingMultiplier() const { return TargetingMultiplier; }
	
	/** 设置瞄准倍率 */
	UFUNCTION()
	void SetTargetingMultiplier(double NewValue) { ChangeValueAndDirty(TargetingMultiplier, NewValue); ApplyInputSensitivity(); }

	/** 获取是否反转垂直轴 */
	UFUNCTION()
	bool GetInvertVerticalAxis() const { return bInvertVerticalAxis; }
	
	/** 设置是否反转垂直轴 */
	UFUNCTION()
	void SetInvertVerticalAxis(bool NewValue) { ChangeValueAndDirty(bInvertVerticalAxis, NewValue); ApplyInputSensitivity(); }

	/** 获取是否反转水平轴 */
	UFUNCTION()
	bool GetInvertHorizontalAxis() const { return bInvertHorizontalAxis; }
	
	/** 设置是否反转水平轴 */
	UFUNCTION()
	void SetInvertHorizontalAxis(bool NewValue) { ChangeValueAndDirty(bInvertHorizontalAxis, NewValue); ApplyInputSensitivity(); }
	
private:
	/** 保存鼠标水平灵敏度 */
	UPROPERTY()
	double MouseSensitivityX = 1.0; // 鼠标水平灵敏度，默认为1.0

	/** 保存鼠标垂直灵敏度 */
	UPROPERTY()
	double MouseSensitivityY = 1.0; // 鼠标垂直灵敏度，默认为1.0

	/** 瞄准时应用的倍率 */
	UPROPERTY()
	double TargetingMultiplier = 0.5; // 瞄准倍率，默认为0.5

	/** 如果为true则垂直视角轴应反转 */
	UPROPERTY()
	bool bInvertVerticalAxis = false; // 反转垂直轴标志，默认为false

	/** 如果为true则水平视角轴应反转 */
	UPROPERTY()
	bool bInvertHorizontalAxis = false; // 反转水平轴标志，默认为false
	
	////////////////////////////////////////////////////////
	// 游戏手柄灵敏度
public:
	/** 获取游戏手柄视角灵敏度预设 */
	UFUNCTION()
	ELyraGamepadSensitivity GetGamepadLookSensitivityPreset() const { return GamepadLookSensitivityPreset; }
	
	/** 设置视角灵敏度预设 */
	UFUNCTION()
	void SetLookSensitivityPreset(ELyraGamepadSensitivity NewValue) { ChangeValueAndDirty(GamepadLookSensitivityPreset, NewValue); ApplyInputSensitivity(); }

	/** 获取游戏手柄瞄准灵敏度预设 */
	UFUNCTION()
	ELyraGamepadSensitivity GetGamepadTargetingSensitivityPreset() const { return GamepadTargetingSensitivityPreset; }
	
	/** 设置游戏手柄瞄准灵敏度预设 */
	UFUNCTION()
	void SetGamepadTargetingSensitivityPreset(ELyraGamepadSensitivity NewValue) { ChangeValueAndDirty(GamepadTargetingSensitivityPreset, NewValue); ApplyInputSensitivity(); }

	/**
	 * 应用输入灵敏度设置
	 */
	void ApplyInputSensitivity();
	
private:
	UPROPERTY()
	ELyraGamepadSensitivity GamepadLookSensitivityPreset = ELyraGamepadSensitivity::Normal; // 游戏手柄视角灵敏度预设，默认为正常
	UPROPERTY()
	ELyraGamepadSensitivity GamepadTargetingSensitivityPreset = ELyraGamepadSensitivity::Normal; // 游戏手柄瞄准灵敏度预设，默认为正常
	
	////////////////////////////////////////////////////////
	/// 脏标记和更改报告
private:
	/**
	 * 更改值并标记为脏
	 * @tparam T 值类型
	 * @param CurrentValue 当前值引用
	 * @param NewValue 新值
	 * @return 如果值已更改返回true，否则返回false
	 */
	template<typename T>
	bool ChangeValueAndDirty(T& CurrentValue, const T& NewValue)
	{
		if (CurrentValue != NewValue)
		{
			CurrentValue = NewValue;
			bIsDirty = true;
			OnSettingChanged.Broadcast(this);
			
			return true;
		}

		return false;
	}

	bool bIsDirty = false; // 脏标记，默认为false
};